//! 当前配置文件加载支持json yaml toml 还需要实现http加载
//! 文件编解码未实现
//! 错误处理需要细化

#![allow(unused_macros, unused_attributes, dead_code)]

use serde;
use serde_json;
use serde_yaml;
use toml;

//------------------------------格式获取

pub fn load_config_from_path<F, P>(t: P) -> anyhow::Result<F>
where
    P: file,
    F: for<'a> serde::de::Deserialize<'a> + for<'de> serde::Deserialize<'de>,
{
    let file_type = t.get_file_type();
    if let FileType::NONE = file_type {
        return    Err(anyhow::anyhow!("unknown file type,only support[json toml yaml]"))
    }
    let f: F = match file_type {
        FileType::JSON => {
            let data = t.get_file_content()?;
            serde_json::from_str(data.as_str())?
        }
        FileType::HTTP => {
            // FIXME HTTP加载方式是错误的，纯属凑数，以后会实现网络文件加载
            unimplemented!();
        }
        FileType::YAML => {
            let data = t.get_file_content()?;
            serde_yaml::from_str(data.as_str())?
        }
        FileType::TOML => {
            let data = t.get_file_content()?;
             toml::from_str(data.as_str())?
        }
        FileType::NONE => {
            return Err(anyhow::anyhow!("unknown file type,only support[json toml yaml]"))
        }
    };
    Ok(f)
}

pub enum FileType {
    JSON,
    HTTP,
    YAML,
    TOML,
    NONE,
}

#[allow(non_camel_case_types)]
pub trait file {
    fn get_file_type(&self) -> FileType;
    fn get_file_path(&self) -> &str;
    fn get_file_content(&self) -> std::io::Result<String>;
}

pub struct File {
    path: &'static str,
}

impl File {
    pub fn new(p: &'static str) -> File {
        File { path: p }
    }
}

impl file for File {
    fn get_file_type(&self) -> FileType {
        if &self.path[0..4].to_lowercase() == "http" {
            return FileType::HTTP;
        } else {
            let filetype = self.path[self.path.len() - 4..].to_lowercase();
            return match filetype.as_str() {
                "json" => FileType::JSON,
                "toml" => FileType::TOML,
                "yaml" => FileType::YAML,
                _ => FileType::NONE,
            };
        }
    }
    fn get_file_path(&self) -> &str {
        self.path
    }
    fn get_file_content(&self) -> std::io::Result<String> {
        std::fs::read_to_string(self.path)
    }
}
